package com.ysstech.reportworld.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.spring.PropertyPreFilters;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.ysstech.common.cache.RedisCacheManager;
import com.ysstech.common.entity.TreeNode;
import com.ysstech.common.exception.BusinessException;
import com.ysstech.common.service.DicvalueService;
import com.ysstech.common.util.DateUtil;
import com.ysstech.common.util.JdbcUtil;
import com.ysstech.reportworld.entity.*;
import com.ysstech.reportworld.enums.ReportWorldEnum;
import com.ysstech.reportworld.enums.ReportWorldStatusEnum;
import com.ysstech.reportworld.mapper.DataReportMapper;
import com.ysstech.reportworld.mapper.ReportMapper;
import com.ysstech.reportworld.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ysstech.common.entity.ColumnInfo;
import com.ysstech.common.entity.TableInfo;
import com.ysstech.reportworld.util.DbConnConfig;
import com.ysstech.reportworld.util.TableInfoUtil;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 报表世界报表信息 服务实现类
 * </p>
 *
 * @author lishuangliang
 * @since 2022-04-28
 */
@Service
public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> implements ReportService {

    @Autowired
    private DataReportMapper dataReportMapper;
    @Autowired
    private DicvalueService dicvalueService;
    @Autowired
    private DataReportService dataReportService;
    @Autowired
    private TableService tableService;
    @Autowired
    private TableDetailService tableDetailService;
    @Autowired
    private DbConnConfig dbConnConfig;
    @Autowired
    private RedisCacheManager redisCacheManager;

    /**
     * 查询报表信息
     *
     * @return
     */
    public List<TreeNode> queryReportTree() throws Exception {
        List<TreeNode> list = new ArrayList<>();
        QueryWrapper<Report> wrapper = new QueryWrapper<>();
        wrapper.orderByAsc("NAME");
        List<Report> listOrganization = this.list(wrapper);
        if (CollectionUtils.isEmpty(listOrganization)) {
            return list;
        }
        list.addAll(this.recursionTree("0", listOrganization));
        return list;
    }

    private List<TreeNode> recursionTree(String id, List<Report> listReport) throws Exception {
        List<TreeNode> list = new ArrayList<>();
        for (Report report : listReport) {
            if (!id.equals(report.getParentId())) {
                continue;
            }
            TreeNode treeNode = ReportReportToNode(report);
            List<TreeNode> children = recursionTree(report.getId(), listReport);
            if (null == children || children.size() == 0) {
                treeNode.setState("open");
            } else {
                treeNode.setChildren(children);
            }
            list.add(treeNode);
        }
        return list;
    }

    /**
     * 将业务功能转化成TreeNode
     */
    private TreeNode ReportReportToNode(Report report) {
        TreeNode node = new TreeNode();
        node.setId(report.getId());
        node.setText(report.getName());
        node.setState("closed");
        node.setChecked(false);
        node.setIconCls("icon-bricks");
        node.setPId(report.getParentId());
        return node;
    }


    /**
     * 获取报表信息
     *
     * @return
     * @throws Exception
     */
    public Map<String, Report> getReportMap() throws Exception {
        Map<String, Report> mapReport = new HashMap<>();
        QueryWrapper<Report> wrapper = new QueryWrapper<>();
        wrapper.orderByAsc("NAME");
        List<Report> listReport = list(wrapper);
        if (CollectionUtils.isEmpty(listReport)) {
            return null;
        }
        for (Report report : listReport) {
            if (null == report || StringUtils.isBlank(report.getId())) {
                continue;
            }
            mapReport.put(report.getId(), report);
        }
        return mapReport;
    }

    /**
     * 查询所有下级报表的报表集合
     *
     * @param id 报表编号
     * @return
     * @throws Exception
     */
    public List<Report> queryListReport(String id) throws Exception {
        if (StringUtils.isBlank(id)) {
            throw new BusinessException("获取报表信息失败，请稍后重试！");
        }
        List<String> list = this.queryReportIds(id);
        QueryWrapper<Report> wrapper = new QueryWrapper<>();
        wrapper.in("ID", list);
        List<Report> listReport = this.list(wrapper);
        return listReport;
    }

    /**
     * 查询所有下级报表的报表id集合
     *
     * @param id
     * @return
     * @throws Exception
     */
    public List<String> queryReportIds(String id) throws Exception {
        if (StringUtils.isBlank(id)) {
            throw new BusinessException("获取报表信息失败，请稍后重试！");
        }
        List<String> strList = new ArrayList<>();
        strList.add(id);
        QueryWrapper<Report> wrapper = new QueryWrapper<>();
        wrapper.orderByAsc("NAME");
        List<Report> list = this.list(wrapper);
        recursionIds(id, strList, list);
        return strList;
    }

    private void recursionIds(String id, List<String> strList, List<Report> list) {
        for (Report report : list) {
            if (!id.equals(report.getParentId())) {
                continue;
            }
            strList.add(report.getId());
            recursionIds(report.getId(), strList, list);
        }
    }

    /**
     * 获取报表对应表信息
     *
     * @return
     */
    @Override
    public List<DataReport> getTableInfo(DataReport dataReport) throws Exception {
        if (null == dataReport || StringUtils.isBlank(dataReport.getReportId())) {
            throw new BusinessException("获取报表对应表信息失败，请稍后重试！");
        }
        List<DataReport> list = dataReportMapper.getTableInfo(dataReport);
        if (CollectionUtils.isEmpty(list)) {
            return null;
        }
        // 报表世界所在分层
        Map<String, String> mapTableLayered = dicvalueService.getCacheDicValueMap(ReportWorldEnum.REPORT_TABLE_LAYERED.getCode());
        // 表类型
        Map<String, String> mapFtype = dicvalueService.getCacheDicValueMap(ReportWorldEnum.REPORT_TABLE_FTYPE.getCode());
        // 表来源
        Map<String, String> maptFsource = dicvalueService.getCacheDicValueMap(ReportWorldEnum.REPORT_TABLE_FSOURCE.getCode());
        for (DataReport report : list) {
            if (null == report) {
                continue;
            }
            //报表世界所在分层
            if (null != mapTableLayered && mapTableLayered.containsKey(String.valueOf(report.getLayered()))) {
                report.setLayered(mapTableLayered.get(String.valueOf(report.getLayered())));
            }
            //表类型
            if (null != mapFtype && mapFtype.containsKey(String.valueOf(report.getFtype()))) {
                report.setFtype(mapFtype.get(String.valueOf(report.getFtype())));
            }
            //表来源
            if (null != maptFsource && maptFsource.containsKey(String.valueOf(report.getFsource()))) {
                report.setFsource(maptFsource.get(String.valueOf(report.getFsource())));
            }
        }
        return list;
    }


    /**
     * 添加报表信息
     *
     * @param report
     * @throws Exception
     */
    public void addReport(Report report) throws Exception {
        if (report == null) {
            throw new BusinessException("获取模块信息失败，请稍后重试！");
        }
        String id = DateUtil.generateUUID();
        report.setId(id);
        report.setStatus(ReportWorldStatusEnum.REPORT_NORMAL.getCode());
        report.setAddUser(redisCacheManager.getLoginUserInfo().getLoginId());
        report.setAddTime(LocalDateTime.now());
        if ("0".equals(report.getParentId())) {
            this.save(report);
            return;
        }
        //添加之前没有下级模块的数据的 添加了以后 模块的关联关系修改到下级
        // 获取该模块的上级之前是不是最明细的
        QueryWrapper<Report> wrapper = new QueryWrapper<>();
        wrapper.eq("PARENT_ID", report.getParentId());
        List<Report> list = this.list(wrapper);
        if (CollectionUtils.isEmpty(list)) { //添加的上级以前没有下级
            // 将关联关系表中原来模块的数据，更新成现在这个新的下级菜单
            UpdateWrapper<DataReport> updateWrapper = new UpdateWrapper<>();
            updateWrapper.eq("REPORT_ID", report.getParentId());
            DataReport dataReport = new DataReport();
            dataReport.setReportId(id);
            dataReport.setStatus(ReportWorldStatusEnum.REPORT_NORMAL.getCode());
            dataReport.setAddUser(redisCacheManager.getLoginUserInfo().getLoginId());
            dataReport.setAddTime(LocalDateTime.now());
            dataReportMapper.update(dataReport, updateWrapper);
        }
        this.save(report);
    }

    /**
     * 修改报表信息
     *
     * @param report
     * @throws Exception
     */
    public void editReport(Report report) throws Exception {
        if (report == null || StringUtils.isBlank(report.getId())) {
            throw new BusinessException("获取模块信息失败，请稍后重试！");
        }
        // 修改之前的上级只有一个下级
        Report oldReport = this.getById(report.getId());
        QueryWrapper<Report> wrapperOld = new QueryWrapper<>();
        wrapperOld.eq("PARENT_ID", oldReport.getId());
        List<Report> listOld = this.list(wrapperOld);
        if (CollectionUtils.isEmpty(listOld)) { //修改之前没有下级
            QueryWrapper<Report> wrapper = new QueryWrapper<>();
            wrapper.eq("PARENT_ID", oldReport.getParentId());
            List<Report> list = this.list(wrapper);
            if (!CollectionUtils.isEmpty(list) && list.size() == 1) {
                // 原来的关联表是这个明细的ID 更新成现在将会变成明细的上级ID
                UpdateWrapper<DataReport> updateWrapper = new UpdateWrapper<>();
                updateWrapper.eq("REPORT_ID", oldReport.getId());
                DataReport dataReport = new DataReport();
                dataReport.setReportId(oldReport.getParentId());
                dataReport.setStatus(ReportWorldStatusEnum.REPORT_NORMAL.getCode());
                dataReport.setAddUser(redisCacheManager.getLoginUserInfo().getLoginId());
                dataReport.setAddTime(LocalDateTime.now());
                dataReportMapper.update(dataReport, updateWrapper);
            }
        }
        report.setEditUser(redisCacheManager.getLoginUserInfo().getLoginId());
        report.setEditTime(LocalDateTime.now());
        //修改后的上级
        if ("0".equals(report.getParentId())) {
            this.updateById(report);
            return;
        }
        // 修改后的这上级 之前是否存在下级
        QueryWrapper<Report> wrapper = new QueryWrapper<>();
        wrapper.eq("PARENT_ID", report.getParentId());
        List<Report> list = this.list(wrapper);
        if (CollectionUtils.isEmpty(list)) { //添加的上级以前没有下级
            // 将关联关系表中原来模块的数据，更新成现在这个新的下级菜单
            UpdateWrapper<DataReport> updateWrapper = new UpdateWrapper<>();
            updateWrapper.eq("REPORT_ID", report.getParentId());
            DataReport dataReport = new DataReport();
            dataReport.setReportId(report.getId());
            dataReport.setStatus(ReportWorldStatusEnum.REPORT_NORMAL.getCode());
            dataReport.setAddUser(redisCacheManager.getLoginUserInfo().getLoginId());
            dataReport.setAddTime(LocalDateTime.now());
            dataReportMapper.update(dataReport, updateWrapper);
        }
        this.updateById(report);
    }

    /**
     * 删除报表信息
     *
     * @param id
     * @throws Exception
     */
    public void delReport(String id) throws Exception {
        if (StringUtils.isBlank(id)) {
            throw new BusinessException("获取删除模块信息失败，请稍后重试！");
        }
        List<String> list = this.queryReportIds(id); //所有下级模块
        Report oldReport = this.getById(id);
        // 删除的这个ID 不是一个一级的
        if ("0".equals(oldReport.getParentId())) {
            // 删除关联关系表中所所有改id包括所有下级的
            QueryWrapper<DataReport> wrapper = new QueryWrapper<>();
            wrapper.in("REPORT_ID", list);
            dataReportMapper.delete(wrapper);
            this.removeByIds(list);
            return;
        }
        UpdateWrapper<DataReport> updateWrapper = new UpdateWrapper<>();
        updateWrapper.in("REPORT_ID", list);
        DataReport dataReport = new DataReport();
        dataReport.setReportId(oldReport.getParentId());
        dataReport.setStatus(ReportWorldStatusEnum.REPORT_NORMAL.getCode());
        dataReport.setAddUser(redisCacheManager.getLoginUserInfo().getLoginId());
        dataReport.setAddTime(LocalDateTime.now());
        dataReportMapper.update(dataReport, updateWrapper);
        this.removeByIds(list);
    }


    /**
     * 用过报表的结果集语句读取用到的表信息到库里
     *
     * @throws Exception
     */

    @Transactional
    public void readTableInfo(String reportId) throws Exception {
        if (StringUtils.isBlank(reportId)) {
            throw new BusinessException("获取报表对应表信息失败，请稍后重试！");
        }
        QueryWrapper<Report> wrapper = new QueryWrapper<>();
        wrapper.eq("ID", reportId);
        Report report = this.getOne(wrapper);
        TableInfoUtil tableInfoUtil = new TableInfoUtil();
        Map<String, String> stringMap = new HashMap<>();
        List<TableInfo> list = tableInfoUtil.getTableInfo(report.getName(), dbConnConfig.getInputConnection());
        try {
            Map<TableInfo, List<ColumnInfo>> map = JdbcUtil.getTableInfoMap(list, dbConnConfig.getInputConnection());
            if (CollectionUtils.isEmpty(map)) {
                throw new BusinessException("数据库没有获取到对应报表的语句用到的表信息，请稍后重试！");
            }
            for (Map.Entry<TableInfo, List<ColumnInfo>> entry : map.entrySet()) {
                TableInfo tableInfo = entry.getKey();
                if (null == tableInfo || StringUtils.isBlank(tableInfo.getName())) {
                    continue;
                }
                if (stringMap.containsKey(tableInfo.getName())) {
                    continue;
                }
                QueryWrapper<Table> wrapper2 = new QueryWrapper<>();
                wrapper2.eq("NAME", tableInfo.getName());
                Table table = tableService.getOne(wrapper2);
                if (null != table) { // 已经存在的表跳过
                    QueryWrapper<DataReport> wrapperp = new QueryWrapper<>();
                    wrapperp.eq("DATA_ID", table.getId());
                    wrapperp.eq("REPORT_ID", report.getId());
                    List<DataReport> reportList = dataReportService.list(wrapperp);
                    if (CollectionUtils.isEmpty(reportList)) {
                        DataReport dataReport = new DataReport();
                        dataReport.setId(DateUtil.generateUUID());
                        dataReport.setReportId(report.getId());
                        dataReport.setDataId(table.getId());
                        dataReport.setDataCode(ReportWorldEnum.REPORT_TABLE_DETAIL_CODE.getCode());
                        dataReportService.save(dataReport);
                    }
                    continue;
                }
                Table addTable = new Table();
                String tableId = DateUtil.generateUUID();
                addTable.setId(tableId);
                addTable.setName(tableInfo.getName());
                addTable.setChineseName(tableInfo.getRemarks());
                //报表落地表处理
                if (StringUtils.isNotBlank(tableInfo.getReportTablename())) {
                    addTable.setLayered(Integer.valueOf(tableInfo.getReportTablename()));
                }
                tableService.save(addTable);
                if (null == report) {
                    continue;
                }
                QueryWrapper<DataReport> wrapperp = new QueryWrapper<>();
                wrapperp.eq("TABLE_ID", tableId);
                wrapperp.eq("REPORT_ID", report.getId());
                List<DataReport> reportList = dataReportService.list(wrapperp);
                if (CollectionUtils.isEmpty(reportList)) {
                    DataReport dataReport = new DataReport();
                    dataReport.setId(DateUtil.generateUUID());
                    dataReport.setReportId(report.getId());
                    dataReport.setDataId(tableId);
                    dataReport.setDataCode(ReportWorldEnum.REPORT_TABLE_CODE.getCode());
                    dataReportService.save(dataReport);
                }
                if (CollectionUtils.isEmpty(entry.getValue())) {
                    log.error(tableInfo.getName() + "没有获取到对应的字段信息!");
                    continue;
                }
                for (ColumnInfo columnInfo : entry.getValue()) {
                    if (null == columnInfo) {
                        continue;
                    }
                    TableDetail tableDetail = TableInfoUtil.getReportTableDetail(columnInfo, tableId);
                    tableDetailService.save(tableDetail);
                }
                stringMap.put(tableInfo.getName(), tableInfo.getName());
            }
        } catch (Exception ex) {
            log.error(ex.getMessage());
        } finally {
        }
    }

    /**
     * 报表数据的json
     *
     * @return
     * @throws Exception
     */
    public String getReportJsonInfo() throws Exception {
        String[] includeProperties = {"id", "parentId", "name", "status"};
        PropertyPreFilters filters = new PropertyPreFilters();
        PropertyPreFilters.MySimplePropertyPreFilter includefilter = filters.addFilter();
        includefilter.addIncludes(includeProperties);
        QueryWrapper<Report> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("STATUS", ReportWorldStatusEnum.getUpgradeToolsZipStatus());
        queryWrapper.orderByAsc("NAME");
        List<Report> list = this.list(queryWrapper);
        return JSONObject.toJSONString(list, includefilter, SerializerFeature.WriteMapNullValue);
    }

}
